Rust Bevy を使ってみたメモ テトリスを作ってみる③

Rust Bevy を使ってみたメモ テトリスを作ってみる③

比較的順調に進んでおります。

今回は
・テトリミノの生成をイベントを使って管理する
・テトリミノをランダムに生成する
・テトリミノを落下させる
の三本立てでやっていきます!!

目次

一気にやってもいいのですが、なんとなく分けたほうがいい気がしたので
GitHubも使ってないですし
bevyのバージョン:0.13.0
rundのバージョン:0.8.5(乱数を生成するクレート)

参考:Rustゲームエンジンbevyでテトリスを作る | makibishi throw
   List of all items in this crate (docs.rs)

テトリミノをイベントを使って管理する

イベントを実装する手順として、

1.イベントを継承した構造体を作る
2.イベントをアプリに登録する
3.イベントを送受信する

という手順を踏んでいきます。

順番にやっていきましょう

1.イベントを継承した構造体を作る

これは簡単ですね

//イベント(テトリミノを生成するタイミング)
#[derive(Event, Debug)]
struct SpawnTetriminoEvent;

ただこれだけです。

2.イベントをアプリに登録する

まぁこれも簡単です

    App::new()
        .add_plugins(DefaultPlugins.set(WindowPlugin {
            primary_window: Some(Window {
                title: "Tetrus".into(),
                resolution: (WINDOW_WIDTH as f32, WINDOW_HEIGHT as f32).into(),
                resizable: false,
                ..default()
            }),
            ..default()
        }))
        .insert_resource(GameTimer(Timer::from_seconds(0.5, TimerMode::Repeating)))
        .add_systems(Startup, (debug, setup))
        .add_systems(Update, (adjust, spawn_tetrimino, tetrimino_fall))

        //ここ!!!
        .add_event::<SpawnTetriminoEvent>()

        .run()

add_systemsとかとは少し登録の仕方が違うので注意ですね

3.イベントを送受信する

個人的にはこれで少し躓きました

まぁ参考にしているサイト様のbevyのバージョンが古いって言うのもあるんですけど、公式Docsが読みにくくて……てか読み方知らない

正直最適な方法なのかはわかりませんがとりあえずエラーなしで実行できたからヨシ!☞

//カメラの生成、色、形リソースの追加
fn setup(
    mut commands: Commands,
    mut spawn_tetrimino_event_writer: EventWriter<SpawnTetriminoEvent>,//イベントライター(イベントを送信)
) {
    commands.spawn(Camera2dBundle::default());
    commands.insert_resource(TetriminoColorAndShape {

        //省略

    });
    //イベントの送信
    spawn_tetrimino_event_writer.send(SpawnTetriminoEvent);
}

//テトリミノの生成
fn spawn_tetrimino(
    mut commands: Commands,
    tetrimino_color_and_shape: Res<TetriminoColorAndShape>,
    mut fancy: Option<Res<TetriminoColorAndShape>>,
    mut spawn_tetrimino_event_reader: EventReader<SpawnTetriminoEvent>,//イベントリーダー(イベントを感知する)
){
    //イベントを感知
    for _ in spawn_tetrimino_event_reader.read() {

        //乱数を生成
        let mut rng = rand::thread_rng();
        let i: u8 = rng.gen();
        let index: usize = (i % 7) as usize;

        //テトリミノを生成
        if let Some(_fancy) = &mut fancy {

            //省略

            }
            println!("spawn {} block", index);
        }else {
            println!("Err");
        }
    }
}

EventWriter<SpawnTetriminoEvent>のsend関数でイベントを送信
EventReader<SpawnTetriminoEvent>のread関数でイベントを受信

って感じかなと

テトリミノをランダムに生成する

とりあえず、Rustゲームエンジンbevyでテトリスを作る | makibishi throw でやっているように、テトリミノを相対位置を使ってテトリミノを表していきます
カラーも公式Docsに書いてある定数を使って楽してます

コードを見た人は気づいたと思うんですけど、実は前回のリソース追加編でさらっと書いてあるんです
前回はリソースに苦しめられてたから書く気が起きませんでした…

詳しい説明は参考にさせていただいたサイトの方を見てください(丸投げ)
てかこのやり方頭いい…私は絶対思い浮かびませんね…

乱数の話に移るんですが、どうやらRustのクレートであるrandは任意の範囲の乱数を生成するには少し手順を踏む必要があるっぽいですね…多分ですけど(英語読めない)

use rand::prelude::*;


//乱数を生成する何かを初期化する(最適なシステムを選択してくれるようです)
let mut rng = rand::thread_rng();

//型の範囲の乱数を生成(u8は適当に選びました 多分あまり関係ない)
let i: u8 = rng.gen();

//Vec型の引数はusizeしか受け付けてないそうなので(7で割った余りを見ることによって0-6までの乱数が生成できる)
let index: usize = (i % 7) as usize;

まぁ上に書いた通りなんですけど、多分こんな感じで任意の範囲の乱数を得ることができるっぽいですね

テトリミノを落下させる

テトリミノを生成しても落下しないとゲームが進行しないので、とりあえず落下だけさせるシステムを作っていきます。

一定間隔でシステムを実行したいので、タイマーを使います

Bevyの公式ブックを最後までやった人はわかると思います。てか私もそのページに書いてあることをそのまま書いただけです。みんなもとりあえず リソース (bevyengine.org) をやってみてください(たいしたことは書いてないですけど)

タイマーを使う手順として

1.タイマーを継承した構造体を作る
2.タイマーをアプリに登録する
3.タイマーをリソースとしてシステムからアクセスする

という手順を踏んでいきます

1タイマーを継承した構造体を作る

2.タイマーをアプリに登録する

面倒なので1.2.は一気にやっちゃいます

//タイマー
#[derive(Resource)]
struct GameTimer(Timer);


fn main() {
    App::new()

        //省略

        //0.5秒間隔でリピートされるように
        .insert_resource(GameTimer(Timer::from_seconds(0.5, TimerMode::Repeating)))

        //省略

        .run()
}

簡単ですね

3.タイマーをリソースとしてシステムからアクセスする

これは リソース (bevyengine.org) に書いてあることをそのまま書いただけですね

//テトリミノの落下
fn tetrimino_fall(
    time: Res<Time>,
    mut game_timer: ResMut<GameTimer>,
    mut tetrimino_query: Query<&mut Position, With<Tetrimino>>,
) {
    if game_timer.0.tick(time.delta()).just_finished() {
        tetrimino_query
            .iter_mut()
            .for_each(|mut pos| {
                //テトリミノのポジションを-1する
                pos.y -= 1;
            });
    }
}

なんでtimeが必要なのかわからないけど動いてるからヨシ!☞

第一回に書いたadjust関数がポジションからトランスフォームを調整してくれるのでこの関数ではポジションを-1するだけでいいというわけですね。adjust君優秀!

まとめ

まとめることは別にないですねぇ。とりあえずもう一回この記事を見返してもろて
それでもわからなかったら多分参考サイトの方を見ていただくとわかるんじゃないかな(丸投げ)
とりあえず目次を貼っておきます

目次

雑記

最近雑記という言葉を知ったので今後はこんな感じでブログを書いていこうかなと

てか、久しぶりにちゃんとした記事を書くと何かだんだんめんどくさくなってきますね
あと、文字の大きさが変えられないっていう重大事実に気づいたので次回までにプラグインをインストールしておきます
めんどくさくなったらここ数回の記事みたいな手抜き記事でお茶を濁していこうかな

話は変わりますが、だいぶテトリスっぽくなってきてモチベが上がっています

リソースに苦しめられているときはモチベ最低だったんですけど、やっぱり形になってくるといいですね!なんか達成感があって!

次回はどこまで進むのか…ここでは明言しないでおきましょう
なんかエラーを吐きそうな気配があるんだよなぁquery関係で…

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です